home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / pmake / doc / index / index.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-15  |  24.3 KB  |  944 lines

  1. /*-
  2.  * index.c --
  3.  *    Postprocessor for ditroff. Takes various things which have been
  4.  *    placed as clear text in the ditroff output and does nice things
  5.  *    with them. The things in clear text are produced using the macros
  6.  *    in tmac.index.
  7.  *
  8.  *    The ditroff output is sent to lpr unless the -t flag is given.
  9.  *
  10.  *
  11.  * Copyright (c) 1988 by the Regents of the University of California
  12.  * Copyright (c) 1988 by Adam de Boor, UC Berkeley
  13.  *
  14.  * Permission to use, copy, modify, and distribute this
  15.  * software and its documentation for any purpose and without
  16.  * fee is hereby granted, provided that the above copyright
  17.  * notice appear in all copies.  The University of California,
  18.  * Berkeley Softworks and Adam de Boor make no representations about
  19.  * the suitability of this software for any purpose.  It is provided
  20.  * "as is" without express or implied warranty.
  21.  *
  22.  *
  23.  */
  24. #ifndef lint
  25. static char rcsid[] =
  26. "$Id: index.c,v 1.3 89/01/08 20:05:00 adam Exp $";
  27. #endif lint
  28.  
  29. #include    <stdio.h>
  30. #include    <ctype.h>
  31. #include    <strings.h>
  32. #include    <sys/file.h>
  33. #include    <sys/signal.h>
  34. extern char *malloc();
  35.  
  36. typedef enum { REF, DEF } refType;
  37.  
  38. typedef struct Ref {    /* Reference to a key */
  39.     int          pageStart;/* Page number on which references started */
  40.     int              pageEnd;  /* Page number where they ended. If pageStart ==
  41.                  * pageEnd, then only one page. */
  42.     struct Ref    *next;    /* Next reference to this */
  43. } Ref;
  44.  
  45. typedef struct Key {    /* An index key */
  46.     char          *key;        /* The text of the key */
  47.     struct Key      *subRefs; /* Sub references (the 'ref' list is ignored) */
  48.     int              defPage;  /* Page where key defined */
  49.     int              defined;  /* True if key defined */
  50.     Ref         *refHead; /* Head of list of references */
  51.     Ref         *refTail; /* Tail of list of references */
  52.     struct Key      *next;    /* Next key in the index */
  53. } Key;
  54.  
  55. typedef struct Index {
  56.     Key              *allKeys; /* List of keys in the index */
  57.     char          *title;   /* Title of the index */
  58.     int              valid;
  59. } Index;
  60.  
  61. Index    *indices = (Index *)NULL;   /* Array of indices */
  62. int    numIndices = 0;                /* Number of indices going */
  63.  
  64. /*
  65.  * Data for verifying section references. secRefs is indexed by the
  66.  * reference number and contains either the expected or actual section number
  67.  * for that reference. If there is a mismatch (excluding the final period),
  68.  * an error is signaled. The array expands as needed to encompass all
  69.  * reference numbers.
  70.  */
  71. typedef struct SecRef {
  72.     char    *expect;        /* Section number expected */
  73.     int        defined;        /* Non-zero if defined */
  74. } SecRef;
  75.  
  76. SecRef    *secRefs = NULL;
  77. int    numSecRefs = 0;
  78.  
  79. #define DITROFF      "/usr/public/troff_p"
  80.  
  81. /*-
  82.  *-----------------------------------------------------------------------
  83.  * strnew --
  84.  *    Duplicate a string into fresh storage and return a pointer to
  85.  *    that storage.
  86.  *
  87.  * Results:
  88.  *    The new string.
  89.  *
  90.  * Side Effects:
  91.  *    Memory is allocated.
  92.  *
  93.  *-----------------------------------------------------------------------
  94.  */
  95. char *
  96. strnew(str)
  97.     char    *str;
  98. {
  99.     char    *newstr;
  100.  
  101.     newstr = malloc(strlen(str)+1);
  102.     (void) strcpy (newstr, str);
  103.     return (newstr);
  104. }
  105.  
  106. /*-
  107.  *-----------------------------------------------------------------------
  108.  * ustrcmp --
  109.  *    Compare two strings in a lexically-unsigned manner. I.e. fold
  110.  *    upper-case letters and lower-case letters together. All other
  111.  *    characters are unaffected.
  112.  *
  113.  * Results:
  114.  *    < 0 if s1 is lexically less, 0 if s1 and s2 are equal and > 0
  115.  *    if s1 is lexically greater than s2.
  116.  *
  117.  * Side Effects:
  118.  *    None.
  119.  *
  120.  *-----------------------------------------------------------------------
  121.  */
  122.  
  123. int
  124. ustrcmp (s1, s2)
  125.     register char *s1;
  126.     register char *s2;
  127. {
  128.     register int  diff;
  129.     register int  c1;
  130.     register int  c2;
  131.  
  132.     if (!s1) {
  133.     s1 = "";
  134.     }
  135.     if (!s2) {
  136.     s2 = "";
  137.     }
  138.     c1 = *s1++;
  139.     c2 = *s2++;
  140.     while (c1 && c2) {
  141.     if (isupper(c1)) {
  142.         /*
  143.          * Force c1 to lower-case
  144.          */
  145.         c1 |= 040;
  146.     }
  147.     if (isupper(c2)) {
  148.         /*
  149.          * Force c2 to lower-case
  150.          */
  151.         c2 |= 040;
  152.     }
  153.     diff = c1 - c2;
  154.     if (diff != 0) {
  155.         /*
  156.          * If there's any difference between the two characters,
  157.          * break out of this loop. Because of the ordering of the subtract,
  158.          * diff is set up to have the correct sign for the return value,
  159.          * so we just return it.
  160.          */
  161.         return (diff);
  162.     } else {
  163.         c1 = *s1++;
  164.         c2 = *s2++;
  165.     }
  166.     }
  167.     if (c1) {
  168.     return (c1);
  169.     } else if (c2) {
  170.     return (c2);
  171.     } else {
  172.     return (0);
  173.     }
  174. }
  175.     
  176.     
  177. /*-
  178.  *-----------------------------------------------------------------------
  179.  * findKey --
  180.  *    Look for a key on a sorted list of keys. If the key cannot be
  181.  *    found, create and initialize a Key structure for it.
  182.  *
  183.  * Results:
  184.  *    The Key structure for the string.
  185.  *
  186.  * Side Effects:
  187.  *    A Key structure may be allocated and linked into the list.
  188.  *
  189.  *-----------------------------------------------------------------------
  190.  */
  191. Key *
  192. findKey (key, headPtr)
  193.     char    *key;
  194.     Key        **headPtr;
  195. {
  196.     register Key  *keyPtr;
  197.     Key              *newKeyPtr;
  198.     int              diff;
  199.     char          *newline = index(key, '\n');
  200.  
  201.     /*
  202.      * First strip off any trailing white-space
  203.      */
  204.     if (newline) {
  205.     *newline = '\0';
  206.     } else {
  207.     newline = key + strlen(key);
  208.     }
  209.  
  210.     while (*--newline == ' ') {
  211.     continue;
  212.     }
  213.     *++newline = '\0';
  214.  
  215.     /*
  216.      * Now look for the key using the unsigned lexical comparison function
  217.      * If it is found, the Key is returned. If the loop goes beyond the
  218.      * last place where the key could be (the list is sorted), the loop
  219.      * is broken, and keyPtr is left pointing at the Key before which the
  220.      * new Key should be linked. headPtr then points to the place to
  221.      * store the new Key's address.
  222.      */
  223.     for (keyPtr = *headPtr; keyPtr; keyPtr = keyPtr->next) {
  224.     diff = ustrcmp (key, keyPtr->key);
  225.     if (diff == 0) {
  226.         return (keyPtr);
  227.     } else if (diff < 0) {
  228.         break;
  229.     } else {
  230.         headPtr = &keyPtr->next;
  231.     }
  232.     }
  233.     newKeyPtr = (Key *) malloc (sizeof(Key));
  234.     newKeyPtr->subRefs = (Key *)NULL;
  235.     newKeyPtr->refHead = newKeyPtr->refTail = (Ref *)NULL;
  236.     newKeyPtr->defined = 0;
  237.     newKeyPtr->key = strnew (key);
  238.     newKeyPtr->next = keyPtr;
  239.     *headPtr = newKeyPtr;
  240.     return (newKeyPtr);
  241. }
  242.  
  243. /*-
  244.  *-----------------------------------------------------------------------
  245.  * PrintKey --
  246.  *    Print a multi-level index key.
  247.  *
  248.  * Results:
  249.  *    None.
  250.  *
  251.  * Side Effects:
  252.  *    Stuff is printed to the give FILE
  253.  *
  254.  *-----------------------------------------------------------------------
  255.  */
  256. void
  257. PrintKey (troff, key)
  258.     FILE    *troff;
  259.     Key        *key;
  260. {
  261.     Key        *subKey;
  262.     Ref        *ref;
  263.  
  264.     fprintf (troff, ".in \\n(INu\n.ti -0.25i\n\\&%s\\ \\ ", key->key);
  265.  
  266.     if (key->defined) {
  267.     fprintf (troff, "\\fB%d\\fP%s", key->defPage,
  268.          key->refHead ? ";\\ " : "");
  269.     }
  270.     /*
  271.      * Print out all the pages which refer to this key. The definition
  272.      * of a key is printed in bold italics.
  273.      */
  274.     if (key->refHead) {
  275.     for (ref = key->refHead; ref; ref = ref->next){
  276.         if (ref->pageStart != ref->pageEnd) {
  277.         fprintf (troff, " %d-%d", ref->pageStart, ref->pageEnd);
  278.         } else {
  279.         fprintf (troff, " %d", ref->pageStart);
  280.         }
  281.         if (ref->next == (Ref *)NULL) {
  282.         putc ('\n', troff);
  283.         } else {
  284.         putc (',', troff);
  285.         }
  286.     }
  287.     } else {
  288.     fputc ('\n', troff);
  289.     }
  290.     
  291.     if (key->subRefs) {
  292.     /*
  293.      * If this entry has subentries, increase the indentation
  294.      * one notch and recurse on all the subentries. When done,
  295.      * decrease the indentation a notch to get back to where we
  296.      * started from...
  297.      */
  298.     fprintf (troff, ".in \\n+(INu\n");
  299.     for (subKey = key->subRefs; subKey; subKey = subKey->next) {
  300.         PrintKey (troff, subKey);
  301.     }
  302.     fprintf (troff, ".in \\n-(INu\n");
  303.     }
  304. }
  305.     
  306. /*-
  307.  *-----------------------------------------------------------------------
  308.  * AddRef --
  309.  *    Given the rest of the line for an index entry, fracture it into
  310.  *    a reference to a single Key structure. The string consists of
  311.  *    a series of space-separated, double-quote enclosed pieces, each
  312.  *    of which is a key. The first piece is the major key and further
  313.  *    pieces specialize that key until the final one is reached. When
  314.  *    the final Key structure is found, place the given reference onto
  315.  *    the end of its reference list.
  316.  *
  317.  * Results:
  318.  *    None.
  319.  *
  320.  * Side Effects:
  321.  *    Of course.
  322.  *
  323.  *-----------------------------------------------------------------------
  324.  */
  325. AddRef (index, page, type, keyString)
  326.     int        index;    /* The index number to which to add the reference */
  327.     int        page;     /* Page number of reference */
  328.     refType type;      /* Type of reference */
  329.     char    *keyString;    /* Start of the entry string. Points to the " */
  330. {
  331.     char    *cp;
  332.     Key        **keyListPtr;
  333.     Key        *key;
  334.     Ref     *ref, **refPtr;
  335.  
  336.     keyListPtr = &indices[index].allKeys;
  337.     keyString++;
  338.  
  339.     /*
  340.      * We loop down the string looking for the end of each piece. When we
  341.      * reach it (hit a doublequote), we look for the key in keyString on
  342.      * the current list (either the list of allKeys or the subRefs list
  343.      * of some key). When we get the Key structure for the current piece,
  344.      * we update keyString to point to the start of the next piece (or the
  345.      * end of the string) and loop.
  346.      */
  347.     for (cp = keyString; *cp; cp++) {
  348.     if (*cp == '"') {
  349.         *cp++ = '\0';
  350.         key = findKey (keyString, keyListPtr);
  351.         keyListPtr = &key->subRefs;
  352.         while (*cp && isspace(*cp)) {
  353.         cp++;
  354.         }
  355.         if (*cp) {
  356.         keyString = ++cp;
  357.         } else {
  358.         keyString = cp;
  359.         break;
  360.         }
  361.     }
  362.     }
  363.  
  364.     if (cp != keyString) {
  365.     /*
  366.      * Some piece left over -- find its Key structure
  367.      */
  368.     key = findKey (keyString, keyListPtr);
  369.     }
  370.  
  371.     /*
  372.      * Link the reference into the final Key we found.
  373.      * If the reference is on the same page as the most recent reference, or
  374.      * just one page away, and it's the same type of reference, then we can
  375.      * smush this reference into the previous one.
  376.      * Otherwise, we have to add a new reference to the end of the list.
  377.      * After this 'if', refPtr will point to the address of a pointer in which
  378.      * the ref should be stuffed to maintain the list structure.
  379.      */
  380.     if (type != DEF) {
  381.     if (key->refTail) {
  382.         if ((key->refTail->pageEnd == page) ||
  383.         (key->refTail->pageEnd + 1 == page)) {
  384.             key->refTail->pageEnd = page;
  385.             return;
  386.         } else {
  387.         refPtr = &key->refTail->next;
  388.         }
  389.     } else {
  390.         refPtr = &key->refHead;
  391.     }
  392.     ref = (Ref *)malloc (sizeof(Ref));
  393.     ref->pageStart = ref->pageEnd = page;
  394.     key->refTail = *refPtr = ref;
  395.     ref->next = (Ref *)NULL;
  396.     } else {
  397.     key->defined = 1;
  398.     key->defPage = page;
  399.     }
  400. }
  401.  
  402. PrintIndex (troff, title, keys)
  403.     FILE    *troff;
  404.     char    *title;
  405.     Key        *keys;
  406. {
  407.     register Key *key;
  408.     register int lastLetter;
  409.  
  410.     /*
  411.      * Now come the initializing macro and the index itself.
  412.      * The index is a two-column beast with a bold-faced letter at the
  413.      * start of each section. The entries in the section are alphabetized
  414.      * and each sub level is shifted right one place.
  415.      */
  416.     fprintf (troff, ".1C\n");
  417.     fprintf (troff, ".LP\n");
  418.     fprintf (troff, ".ce\n");
  419.     fprintf (troff, "\\fB\\s+2%s\\s0\\fP\n", title);
  420.     fprintf (troff, ".sp 2v\n");
  421.     fprintf (troff, ".2C\n");
  422.     lastLetter = '\0';
  423.     
  424.     /*
  425.      * Now Print out the top-level entries in the index. The most recent
  426.      * section letter printed is stored in the variable 'lastLetter'.
  427.      * If it is a letter, it is upper-case. Each time the first letter of
  428.      * a key doesn't match lastLetter, a new section letter is printed
  429.      * and lastLetter set to the new section letter.
  430.      */
  431.     for (key = keys; key != (Key *)NULL; key = key->next) {
  432.     char c = islower(key->key[0]) ? toupper(key->key[0]) : key->key[0];
  433.     
  434.     if (c != lastLetter) {
  435.         fprintf (troff, ".sp 1v\n");
  436.         fprintf (troff, ".in 0.25i\n");
  437.         fprintf (troff, ".ti -0.25i\n");
  438.         fprintf (troff, ".nr IN 0.5i 0.25i\n");
  439.         if (c == '\\') {
  440.         fprintf (troff, "\\s+2\\fB\\e\\fP\\s0\n");
  441.         } else {
  442.         fprintf (troff, "\\&\\s+2\\fB%c\\fP\\s0\n", c);
  443.         }
  444.         fprintf (troff, ".sp 0.5v\n");
  445.         lastLetter = c;
  446.     }
  447.     PrintKey (troff, key);
  448.     }
  449. }
  450.  
  451. main (argc, argv)
  452.     int        argc;
  453.     char    **argv;
  454. {
  455.     char    line[256];                    /* Input line */
  456.     char    *printer = (char *)NULL;    /* Printer to give to lpr */
  457.     FILE    *out = (FILE *)NULL;        /* Output file (stdout or pipe) */
  458.     char    typesetter[64];             /* Typesetter used for input file
  459.                      * (passed to second ditroff) */
  460.     int        inPipes[2];                    /* Pipe to ditroff's input */
  461.     int        outid;                    /* Stream open to ditroff's output
  462.                      * file */
  463.     static char outFile[] = "/tmp/indexXXXXXX";/* File for ditroff's output */
  464.     int        pid;                      /* Process ID of ditroff */
  465.     char    *LH = NULL;                    /* Left header string */
  466.     char    *CH = NULL;                    /* Center header string */
  467.     char    *RH = NULL;                    /* Right header string */
  468.     char    *EH = NULL;                    /* Even header string */
  469.     char    *OH = NULL;                    /* Odd header string */
  470.     char    *LF = NULL;                    /* Left footer string */
  471.     char    *CF = NULL;                    /* Center footer string */
  472.     char    *RF = NULL;                    /* Right footer string */
  473.     char    *EF = NULL;                    /* Even footer string */
  474.     char    *OF = NULL;                    /* Odd footer string */
  475.     int        pageInit = 0;               /* Initial page number for index */
  476.     Key        *key;
  477.     Ref     *ref;
  478.     int        i;
  479.     int        errors = 0;                    /* Number of section-reference errors
  480.                      * encountered */
  481.     int        lprPID;
  482.  
  483.  
  484.     /*
  485.      * Process all arguments. Don't bitch about unknown ones...
  486.      */
  487.     while (--argc) {
  488.     argv++;
  489.     if (**argv == '-') {
  490.         switch (argv[0][1]) {
  491.         case 'P':
  492.             printer = *argv;
  493.             break;
  494.         case 't':
  495.             out = stdout;
  496.             break;
  497.         }
  498.     } else {
  499.         freopen (*argv, "r", stdin);
  500.     }
  501.     }
  502.  
  503.     /*
  504.      * If -t flag not given, set "out" to be a pipe to an lpr process. All
  505.      * our output is sent through the 'out' file, including that of the
  506.      * secondary DITROFF process, after being suitably filtered, of course.
  507.      */
  508.     if (out == (FILE *)NULL) {
  509.     char      *lprArgv[4];
  510.     int       pipes[2];
  511.  
  512.     lprArgv[0] = "/usr/ucb/lpr";
  513.     lprArgv[1] = "-n";
  514.     lprArgv[2] = printer;
  515.     lprArgv[3] = (char *)0;
  516.  
  517.     pipe(pipes);
  518.     lprPID = vfork();
  519.     if (lprPID == 0) {
  520.         dup2 (pipes[0], 0);
  521.         close (pipes[0]);
  522.         close (pipes[1]);
  523.         execv (lprArgv[0], lprArgv);
  524.         _exit(2);
  525.     } else if (lprPID == -1) {
  526.         fprintf (stderr, "index: could not fork\n");
  527.         exit(1);
  528.     } else {
  529.         close (pipes[0]);
  530.         out = fdopen (pipes[1], "w");
  531.     }
  532.     } else {
  533.     lprPID = 0;
  534.     }
  535.  
  536.     /*
  537.      * Initialize the section references array, since some systems
  538.      * bitch about realloc(NULL, n);
  539.      */
  540.     numSecRefs = 1;
  541.     secRefs = (SecRef *)calloc(1, sizeof(SecRef));
  542.  
  543.     /*
  544.      * First filter the input file, removing the 'stop' command and
  545.      * extracting the clear-text things placed in the output by the
  546.      * various macros. All clear-text commands are on a line by themselves
  547.      * and begin with the letter 'X'.
  548.      */
  549.     while (fgets (line, sizeof(line), stdin) != (char *)NULL) {
  550.     switch (line[0]) {
  551.         case 'x':
  552.         switch (line[2]) {
  553.             case 's':
  554.             /*
  555.              * This line is the 'stop' command to the driver.
  556.              * We don't want the driver to stop, however, so we
  557.              * just remove the command and tack on the index to
  558.              * end of the output we send to the output file.
  559.              */
  560.             continue;
  561.             case 'T': 
  562.             /*
  563.              * This is the specification of the typesetter used for
  564.              * the original output. We extract the name from the
  565.              * line and pass it on to the second ditroff process
  566.              * which we will invoke later.
  567.              */
  568.             sscanf (line, "x T %s", &typesetter[2]);
  569.             typesetter[0] = '-';
  570.             typesetter[1] = 'P';
  571.             default:
  572.             /*
  573.              * Any other driver-control line can be printed, as
  574.              * it won't do any harm.
  575.              */
  576.             fputs (line, out);
  577.             break;
  578.         }
  579.         break;
  580.         case 'X':
  581.         /*
  582.          * This is one of ours. The possible lines are:
  583.          *     X ENTRY        An entry for an index
  584.          *    X TITLE        Title for an index
  585.          *    X PN        The page number *before* the index.
  586.          *    X HL
  587.          *    X HC
  588.          *    X HR
  589.          *    X HO
  590.          *    X HE        The Left, Center, Right, Odd or Even header
  591.          *    X FL
  592.          *    X FC
  593.          *     X FR
  594.          *    X FO
  595.          *    X FE        The Left, Center, Right, Odd or Even header
  596.          *    X REF        A section reference.
  597.          *    X DEF        The resolution of an earlier (or later)
  598.          *                section reference.
  599.          */
  600.         switch (line[2]) {
  601.             case 'E': {
  602.             register char    *cp;
  603.             register int     page;
  604.             register int    index;
  605.             refType            type;
  606.             
  607.             cp = &line[sizeof("X ENTRY")];
  608.             for (page = 0; *cp != ' '; cp++) {
  609.                 page = page * 10 + *cp - '0';
  610.             }
  611.             cp++;
  612.             for (index = 0; *cp != ' '; cp++) {
  613.                 index = index * 10 + *cp - '0';
  614.             }
  615.             cp++;
  616.             type = *cp++ == 'r' ? REF : DEF;
  617.             cp += 3;
  618.             if (index >= numIndices) {
  619.                 /*
  620.                  * A new index is being started. Allocate room for
  621.                  * it and initialize all those not yet initialized
  622.                  * (in case the person starts in on index 2...),
  623.                  * then mark the new index valid.
  624.                  */
  625.                 if (indices == (Index *)NULL) {
  626.                 indices = (Index *)malloc((index + 1) *
  627.                               sizeof(Index));
  628.                 } else {
  629.                 indices = (Index *)realloc(indices,
  630.                                (index + 1) *
  631.                                sizeof(Index));
  632.                 }
  633.                 while (numIndices <= index) {
  634.                 indices[numIndices].allKeys = (Key *)NULL;
  635.                 indices[numIndices].title = "INDEX";
  636.                 indices[numIndices].valid = 0;
  637.                 numIndices++;
  638.                 }
  639.             }
  640.             indices[index].valid = 1;
  641.             AddRef (index, page, type, cp);
  642.             break;
  643.             }
  644.             case 'T': {
  645.             register char *cp;
  646.             register int index;
  647.  
  648.             cp = &line[sizeof("X TITLE")];
  649.             for (index = 0; *cp != ' '; cp++) {
  650.                 index = index * 10 + *cp - '0';
  651.             }
  652.             cp++;
  653.             if (index >= numIndices) {
  654.                 /*
  655.                  * A new index is being started. Allocate room for
  656.                  * it and initialize all those not yet initialized
  657.                  * (in case the person starts in on index 2...),
  658.                  * then mark the new index valid.
  659.                  */
  660.                 if (indices == (Index *)NULL) {
  661.                 indices = (Index *)malloc((index + 1) *
  662.                               sizeof(Index));
  663.                 } else {
  664.                 indices = (Index *)realloc(indices,
  665.                                (index + 1) *
  666.                                sizeof(Index));
  667.                 }
  668.                 while (numIndices <= index) {
  669.                 indices[numIndices].allKeys = (Key *)NULL;
  670.                 indices[numIndices].title = "INDEX";
  671.                 indices[numIndices].valid = 0;
  672.                 numIndices++;
  673.                 }
  674.             }
  675.             /*
  676.              * Note that an index isn't valid until something has
  677.              * been entered in it...
  678.              */
  679.             indices[index].title = strnew(cp);
  680.             for (cp = indices[index].title;
  681.                  *cp && (*cp != '\n'); cp++)
  682.                 ;
  683.             *cp = '\0';
  684.             break;
  685.             }
  686.             case 'H':
  687.             switch (line[3]) {
  688.                 case 'C':
  689.                 CH = strnew(&line[5]);
  690.                 break;
  691.                 case 'L':
  692.                 LH = strnew(&line[5]);
  693.                 break;
  694.                 case 'R':
  695.                 RH = strnew(&line[5]);
  696.                 break;
  697.                 case 'O':
  698.                 OH = strnew(&line[5]);
  699.                 break;
  700.                 case 'E':
  701.                 EH = strnew(&line[5]);
  702.                 break;
  703.             }
  704.             break;
  705.             case 'F':
  706.             switch (line[3]) {
  707.                 case 'C':
  708.                 CF = strnew(&line[5]);
  709.                 break;
  710.                 case 'L':
  711.                 LF = strnew(&line[5]);
  712.                 break;
  713.                 case 'R':
  714.                 RF = strnew(&line[5]);
  715.                 break;
  716.                 case 'O':
  717.                 OF = strnew(&line[5]);
  718.                 break;
  719.                 case 'E':
  720.                 EF = strnew(&line[5]);
  721.                 break;
  722.             }
  723.             break;
  724.             case 'P':
  725.             pageInit = atoi (&line[5]);
  726.             break;
  727.             case 'R':
  728.             case 'D':
  729.             {
  730.             int lineno = atoi(&line[6]);
  731.             int refNum;
  732.             char *cp, *cp2;
  733.  
  734.             cp = index(&line[6], ' ') + 1;
  735.             refNum = atoi(cp);
  736.             
  737.             if (refNum >= numSecRefs) {
  738.                 secRefs =
  739.                 (SecRef *)realloc(secRefs,
  740.                           (refNum+10)*sizeof(SecRef));
  741.                 bzero(&secRefs[numSecRefs],
  742.                   (refNum+10-numSecRefs)*sizeof(SecRef));
  743.                 numSecRefs = refNum+10;
  744.             }
  745.             /*
  746.              * Isolate the section number
  747.              */
  748.             cp = index(cp, ' ') + 1;
  749.             cp2 = rindex(cp, '.');
  750.             if (cp2 == NULL || cp2[1] != '\n') {
  751.                 /*
  752.                  * No trailing . -- find the end of the line
  753.                  * instead.
  754.                  */
  755.                 cp2 = index(cp, '\n');
  756.             }
  757.             *cp2 = '\0';
  758.  
  759.             if (secRefs[refNum].expect == NULL) {
  760.                 /*
  761.                  * No reference yet -- store this section number
  762.                  * as the expected one.
  763.                  */
  764.                 secRefs[refNum].expect = malloc(cp2 - cp + 1);
  765.                 strcpy(secRefs[refNum].expect, cp);
  766.                 if (line[2] == 'D') {
  767.                 secRefs[refNum].defined = 1;
  768.                 }
  769.             } else if ((line[2]=='D') && secRefs[refNum].defined) {
  770.                 fprintf(stderr,
  771.                     "line %d: reference %d multi-defined\n",
  772.                     lineno, refNum);
  773.                 errors++;
  774.             } else if (strcmp(secRefs[refNum].expect, cp) != 0) {
  775.                 fprintf(stderr,
  776.                     "line %d: reference %d invalid -- ",
  777.                     lineno, refNum);
  778.                 if (secRefs[refNum].defined) {
  779.                 fprintf(stderr, "referred to as %s, ", cp);
  780.                 fprintf(stderr, "defined as %s\n",
  781.                     secRefs[refNum].expect);
  782.                 } else if (line[2] == 'D') {
  783.                 fprintf(stderr, "referred to as %s, ",
  784.                     secRefs[refNum].expect);
  785.                 fprintf(stderr, "defined as %s\n", cp);
  786.                 /*
  787.                  * Store in correct definition
  788.                  */
  789.                 free(secRefs[refNum].expect);
  790.                 secRefs[refNum].expect = malloc(cp2-cp+1);
  791.                 strcpy(secRefs[refNum].expect, cp);
  792.                 secRefs[refNum].defined = 1;
  793.                 } else {
  794.                 fprintf(stderr, "referred to as %s and %s\n",
  795.                     secRefs[refNum].expect, cp);
  796.                 }
  797.                 errors++;
  798.             } else if (line[2] == 'D') {
  799.                 /*
  800.                  * Current string OK, now mark as defined.
  801.                  */
  802.                 secRefs[refNum].defined = 1;
  803.             }
  804.             break;
  805.             }
  806.         }
  807.         break;
  808.         default:
  809.         fputs (line, out);
  810.         break;
  811.     }
  812.     }
  813.  
  814.     for (i = 0; i < numSecRefs; i++) {
  815.     if (secRefs[i].expect && !secRefs[i].defined) {
  816.         fprintf(stderr, "Undefined reference %d -- expected %s\n", i,
  817.             secRefs[i].expect);
  818.         errors++;
  819.     }
  820.     }
  821.  
  822.     if (errors) {
  823.     /*
  824.      * Stop now if we got errors, making sure to stop the lpr if it's in
  825.      * progress.
  826.      */
  827.     if (lprPID != 0) {
  828.         if (kill(lprPID, SIGINT) < 0) {
  829.         perror("couldn't kill lpr");
  830.         }
  831.     }
  832.     exit(errors);
  833.     }
  834.     
  835.     /*
  836.      * Start up the secondary ditroff process to format the index nicely.
  837.      * We have one pipe to its input, for writing the index, and one pipe
  838.      * from its output, for capturing the resulting ditroff text.
  839.      */
  840.     pipe (inPipes);
  841.     outid = mkstemp (outFile);
  842.  
  843.     pid = vfork();
  844.     if (pid == 0) {
  845.     dup2 (inPipes[0], 0);
  846.     dup2 (outid, 1);
  847.     close(inPipes[0]); close (inPipes[1]);
  848.     close(outid);
  849.     if (out != stdout) {
  850.         close (fileno(out));
  851.     }
  852. #ifndef DEBUG
  853.     execl (DITROFF, "troff_p", typesetter, "-t", "-rv1", "-ms", 0);
  854. #endif DEBUG
  855.     _exit(2);
  856.     } else if (pid == -1) {
  857.     perror ("vfork");
  858.     exit(3);
  859.     } else {
  860.     /*
  861.      * Once the ditroff is off and running, we create another FILE for
  862.      * ease of writing the indices. This FILE is used at first for writing
  863.      * the indices, and then for reading the result.
  864.      */
  865.     FILE        *troff;
  866.     int       cpid;
  867.     
  868.     close (inPipes[0]);
  869.     close (outid);
  870. #ifndef DEBUG
  871.     troff = fdopen (inPipes[1], "w");
  872. #else
  873.     troff = stderr;
  874. #endif DEBUG    
  875.  
  876.     /*
  877.      * First set up the environment. Note that this does not capture all
  878.      * the important things, such as line spacing, point size, font,
  879.      * etc., but it does capture the most important ones, I think. These
  880.      * are the page number and the various headers and footers.
  881.      * The headers and footers end in \n, so no need to print it...
  882.      */
  883.     fprintf (troff, ".pn %d\n", pageInit+1);
  884.     fprintf (troff, ".ec \7\n");
  885.     if (LH) {
  886.         fprintf (troff, ".ds LH %s", LH);
  887.     }
  888.     if (CH) {
  889.         fprintf (troff, ".ds CH %s", CH);
  890.     }
  891.     if (RH) {
  892.         fprintf (troff, ".ds RH %s", RH);
  893.     }
  894.     if (LF) {
  895.         fprintf (troff, ".ds LF %s", LF);
  896.     }
  897.     if (CF) {
  898.         fprintf (troff, ".ds CF %s", CF);
  899.     }
  900.     if (RF) {
  901.         fprintf (troff, ".ds RF %s", RF);
  902.     }
  903.     if (EH) {
  904.         fprintf (troff, ".EH %s", EH);
  905.     }
  906.     if (OH) {
  907.         fprintf (troff, ".OH %s", OH);
  908.     }
  909.     if (EF) {
  910.         fprintf (troff, ".EF %s", EF);
  911.     }
  912.     if (OF) {
  913.         fprintf (troff, ".OF %s", OF);
  914.     }
  915.     fprintf (troff, ".ec \\\n");
  916.     for (i = 0; i < numIndices; i++) {
  917.         if (indices[i].valid) {
  918.         PrintIndex (troff, indices[i].title, indices[i].allKeys);
  919.         }
  920.     }
  921.     (void) fclose (troff);
  922.     /*
  923.      * Wait for ditroff to finish before going for its output...
  924.      */
  925.     while ((cpid = wait(0)) != pid && (cpid != -1))
  926.         ;
  927.     
  928.     troff = fopen (outFile, "r");
  929.     if (troff == (FILE *)NULL) {
  930.         perror (outFile);
  931.     } else {
  932.         while (fgets (line, sizeof(line), troff) != NULL) {
  933.         if (line[0] != 'x' || line[2] != 'i') {
  934.             fputs (line, out);
  935.         }
  936.         }
  937.         (void) fclose (troff);
  938.     }
  939.     (void) fclose (out);
  940.     
  941.     (void) unlink (outFile);
  942.     }
  943. }
  944.